import * as step from '@flow-step/step-toolkit'
import OpenApi, * as $OpenApi from '@alicloud/openapi-client';
import FC20230330, * as $FC20230330 from '@alicloud/fc20230330';
import Util, * as $Util from '@alicloud/tea-util';
import process from 'process'
import {convertToUpperCase} from './util'
import {getParams} from './params'

function getRequiredEnv(envName: string): string {
    const value = process.env[envName]
    if (!value) throw new Error(`Missing required variable: ${envName}`)
    return value
}

enum CodeSourceType {
    OSS_ZIP = "OSS_ZIP",
    CUSTOM_IMAGE = "CUSTOM_IMAGE"
}

async function runStep(): Promise<void> {
    const params = getParams()
    step.info(`PIPELINE_ID=${params.pipelineID}`)
    step.info(`PIPELINE_NAME=${params.pipelineName}`)
    step.info(`BUILD_NUMBER=${params.buildNumber}`)
    step.info(`WORK_SPACE=${params.workSpace}`)
    step.info(`PROJECT_DIR=${params.projectDir}`)
    step.info(`BUILD_JOB_ID=${params.buildJobID}`)

    const functionName = getRequiredEnv("FUNC_NAME")
    step.info(`deploy function =${functionName}`)

    const codeSourceType = getRequiredEnv("SOURCE_TYPE") as CodeSourceType
    step.info(`code source type =${codeSourceType}`)

    const fcClient = await getFCClient()
    let updateFunctionRequest = new $FC20230330.UpdateFunctionRequest()

    let body = {}
    if (codeSourceType === CodeSourceType.OSS_ZIP) {
        const ossBucketName =  getRequiredEnv("OSS_BUCKET")
        const ossObjectName =  getRequiredEnv("OSS_OBJECT_NAME")
        body = {
            code: {
                ossBucketName: ossBucketName,
                ossObjectName: ossObjectName,
            },
        };
    } else if (codeSourceType === CodeSourceType.CUSTOM_IMAGE) {
        const imageURL =  getRequiredEnv("IMAGE")
        body = {
            customContainerConfig: {
                image: imageURL,
            },
        }
    } else {
        throw new Error(`unknown code source type: ${codeSourceType}`)
    }

    const regionId = getRequiredEnv("REGION_ID")
    step.interaction.addLink("函数控制台", `https://fcnext.console.aliyun.com/${regionId}/functions/${functionName}`)
    step.info(`函数控制台链接: https://fcnext.console.aliyun.com/${regionId}/functions/${functionName}`);
    try {
        let runtime = new $Util.RuntimeOptions({ });
        let request = new $OpenApi.OpenApiRequest({
            body: body,
        });
        console.log(body)
        let params = createApiInfo(functionName);
        let resp =  fcClient.callApi(params, request, runtime);
        step.info(`update function ${functionName} success`)
    } catch (error) {
        throw new Error(`Failed to deploy FC Function: ${error instanceof Error ? error.stack : error}`)
    }
}

function createApiInfo(functionName: string): $OpenApi.Params {
    const replacedName = functionName.replace(/\$/g, '%24');
    let params = new $OpenApi.Params({
        action: "UpdateFunction",
        version: "2023-03-30",
        protocol: "HTTPS",
        method: "PUT",
        authType: "AK",
        style: "FC",
        pathname: `/2023-03-30/functions/${replacedName}`,
        reqBodyType: "json",
        bodyType: "json",
    });
    return params;
}

export async function getFCClient() {
    const certificate = await getFCCertificate()
    step.addOutput(`FC_ACCESS_KEY_ID=${certificate.accessKeyId}`)
    step.addOutput(`FC_ACCESS_KEY_SECRET=${certificate.accessKeySecret}`)
    step.addOutput(`FC_SECURITY_TOKEN=${certificate.securityToken}`)
    step.addOutput(`FC_ACCOUNT_ID=${certificate.accountId}`)

    const regionId = getRequiredEnv("REGION_ID")
    const config = new $OpenApi.Config({
        accessKeyId: certificate.accessKeyId,
        accessKeySecret: certificate.accessKeySecret,
        securityToken: certificate.securityToken,
        endpoint: `${certificate.accountId}.${regionId}.fc.aliyuncs.com`
    });

    return  Promise.resolve(new FC20230330(config));
}

export async function getFCCertificate(){
    const flowJobToken: string | undefined =
        process.env['FLOW_JOB_TOKEN']
    if (flowJobToken == undefined) {
        throw new Error('missing FLOW_JOB_TOKEN')
    }
    const certificate = await step.certificate.getRamStsCertificate(flowJobToken,process.env.SERVICE_CONNECTION_ID as string)

    if (certificate === undefined || certificate.accessKeyId === "") {
        throw new Error(`get RamStsCertificate but error: ${JSON.stringify(certificate)}`)
    }
    step.debug(`get RamStsCertificate data: ${JSON.stringify(certificate)}`)

    return Promise.resolve(certificate)
}

runStep()
    .then(function() {
        step.success('run step successfully!')
    })
    .catch(function(err: Error) {
        step.error(err.message)
        process.exit(-1)
    })
